package helper

import (
	"errors"
	"math/rand"
	"strconv"
	"strings"
	"time"
	
	"collecter/app/lang"

	"github.com/shopspring/decimal"
)

type ReturnType struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

/*
*
ReturnMsg 接口统一格式返回函数
errCode int 错误号
*/
func ReturnMsg(errCode int) ReturnType {
	var rst = ReturnType{
		Code: errCode,
		Msg:  lang.CodeMessage(errCode),
		Data: "",
	}
	return rst
}

/**
*  GetRandNumber
*  @Description: 获取某个范围的随机数
*  @param min 范围最小值
*  @param max 范围最大值
*  @return int
 */
func GetRandNumber(min int, max int) int {
	if min > max {
		min, max = max, min
	}
	timeObj := time.Now()
	rand.Seed(timeObj.UnixMicro())
	randNumber := rand.Intn(max)
	if randNumber < min {
		return max - randNumber
	}
	return randNumber
}

/**
*  DatesTimestamp
*  @Description: 获取n天前/后 的开始、结束时间戳, days 为负则代表取前几天，为正则代表取后几天，0则为今天
*  @param days 天数
*  @return int64 时间戳
 */

func DatesTimestamp(days int) map[string]int64 {
	rst := make(map[string]int64)
	// 时区
	timeZone := time.FixedZone("CST", 8*3600) // 东八区
	nowTime := time.Now().In(timeZone)
	addTimeObj := nowTime.AddDate(0, 0, days)
	start := time.Date(addTimeObj.Year(), addTimeObj.Month(), addTimeObj.Day(), 0, 0, 0, 0, nowTime.Location()).Unix()
	end := time.Date(addTimeObj.Year(), addTimeObj.Month(), addTimeObj.Day(), 23, 59, 59, 0, nowTime.Location()).Unix()
	rst["start"] = start
	rst["end"] = end
	return rst
}

/**
*  AccurateComputation
*  @Description: 浮点数精确计算，支持常规的 加减乘除
*  @param val1 第一个操作数
*  @param val2 第二个操作数
*  @param action 操作，add：加法；sub：减法；mul：乘法；div：除法
*  @param digits 保留小数点后位数
*  @return error
*  @return float64 精确计算得到的结果
 */
func AccurateComputation(val1 float64, val2 float64, action string, digits int32) (error, float64) {
	var rst float64
	var instance decimal.Decimal

	if "div" == action && val2 == 0 {
		return errors.New(lang.CodeMessage(9)), rst
	}

	v1 := decimal.NewFromFloat(val1)
	v2 := decimal.NewFromFloat(val2)
	action = strings.ToLower(action)
	switch action {
	case "add":
		instance = v1.Add(v2)
	case "sub":
		instance = v1.Sub(v2)
	case "mul":
		instance = v1.Mul(v2)
	case "div":
		instance = v1.Div(v2)
	}
	rst, _ = instance.Round(digits).Float64()
	return nil, rst
}

/**
*  GenerateOrderSn
*  @Description: 生成订单号
*  @param prefix 订单号前缀
*  @return string 订单号
 */
func GenerateOrderSn(prefix string) string {
	timeObj := time.Now()
	timeNow := timeObj.Format("20060102150405")

	randNumber := GetRandNumber(1000, 10000)
	sn := strings.ToUpper(prefix) + "-" + timeNow + "-" + strconv.Itoa(randNumber)
	return sn
}

/**
 * GenerateRandomString
 * @Description: 生成随机字符串
 * @param length 字符串长度
 * @param allowedChars 允许的字符列表
 * @return string
 */
func GenerateRandomString(length int, allowedChars ...[]rune) string {
	var defaultLetters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
	var letters []rune

	if len(allowedChars) == 0 {
		letters = defaultLetters
	} else {
		letters = allowedChars[0]
	}

	b := make([]rune, length)
	lettersLen := len(letters)
	for i := range b {
		b[i] = letters[rand.Intn(lettersLen)]
	}
	return string(b)
}

/**
 * GenerateOutTradeNo
 * @Description: 生成支付流水号
 * @param prefix 前缀
 * @return string
 */
func GenerateOutTradeNo(prefix string) string {
	timeObj := time.Now()
	timeNow := timeObj.Format("20060102150405")

	str := GenerateRandomString(8)
	outTradeNo := strings.ToUpper(prefix) + "-" + timeNow + "-" + str
	return outTradeNo
}

/**
 * GetAgeInIdCard
 * @Description: 根据身份证号获取年龄
 * @param idCardNo 身份证号
 * @param returnFormat 返回格式， int：字符串形式的时间戳；string：字符串日期
 * @return error
 * @return string
 */
func GetAgeInIdCard(idCardNo string, returnFormat string) (error, string) {
	if len(idCardNo) == 0 {
		return nil, ""
	}
	ymd := idCardNo[6:14]
	year := ymd[0:5]
	month := ymd[5:7]
	day := ymd[6:8]
	birthday := year + "-" + month + "-" + day
	if "int" == returnFormat {
		stamp, _ := time.ParseInLocation("2006-01-02", birthday, time.Local) //使用parseInLocation将字符串格式化返回本地时区时间
		birthdayInt := stamp.Unix()
		return nil, strconv.Itoa(int(birthdayInt))
	} else {
		return nil, birthday
	}
}

/**
 * GetBankNameByCode
 * @Description: 根据银行代码获取银行名称
 * @param code 银行代码
 * @return error
 * @return string
 */
/*func GetBankNameByCode(code string) (error, string) {
	if len(code) == 0 {
		return errors.New(lang.CodeMessage(6)), ""
	}
	if bankname, ok := conf.BankCodeMaps[code]; !ok {
		return errors.New(lang.CodeMessage(10002)), ""
	} else {
		return nil, bankname
	}
}*/

/*
 *  snakeString
 * @Description: 驼峰（大驼峰和小驼峰）转小写+下划线
 * @param str
 * @return string
 */
func SnakeString(str string) string {
	if len(str) == 0 {
		return str
	}
	rst := make([]rune, 0, 0)
	for i, v := range str {
		if v >= 'A' && v <= 'Z' && i != 0 {
			rst = append(rst, '_')
		}
		rst = append(rst, v)
	}
	return strings.ToLower(string(rst))
}

/*
 *  CamelString
 * @Description: 蛇形字符串（小写+下划线）转换为驼峰
 * @param str
 * @param smallCamel 是否转换为小驼峰
 * @return string
 */
func CamelString(str string, smallCamel bool) string {
	if len(str) == 0 {
		return str
	}
	strs := strings.Split(str, "_")
	rst := make([]byte, 0, 0)
	for i, v := range strs {
		if smallCamel && i == 0 {
			rst = append(rst, strings.ToLower(v)...)
		} else {
			first := v[0]
			if first >= 'a' && first <= 'z' {
				first = first - 32
			}
			rst = append(rst, first)
			rst = append(rst, []byte(v[1:])...)
		}
	}
	return string(rst)
}
